home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Languguage OS 2
/
Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO
/
gnu
/
ae.lha
/
ae
/
AE
/
ae-sparc.h
< prev
next >
Wrap
C/C++ Source or Header
|
1990-02-28
|
13KB
|
454 lines
/* AE program profiling system.
Machine-specific definitions for SPARC processors.
Copyright (C) 1990 by James R. Larus. (larus@cs.wisc.edu)
AE and AEC are free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 1, or (at your option) any
later version.
AE and AEC are distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU General Public License
along with GNU CC; see the file COPYING. If not, write to James R.
Larus, Computer Sciences Department, University of Wisconsin--Madison,
1210 West Dayton Street, Madison, WI 53706, USA or to the Free
Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
/* $Header: /var/home/larus/AE/AE/RCS/ae-sparc.h,v 2.0 90/02/09 17:21:58 larus Exp Locker: larus $ */
/* Define the base and bounds of the AE buffer that accumulates events in
the executing program. */
/* The pointer to the AE Buffer can either be in a register or in a
variable stored in memory. If it is in a register, AE_BUFFER_REG
contains the register's name, as a string. If it is in memory,
AE_BUFFER_VAR contains the variable's name as a string.
MAKE_AE_BUFFER_POINTER returns an rtx expression for this pointer. */
/* On SPARC, we use base and bounds registers (%g4 and %g6,
respectively). */
#define AE_BUFFER_REG "%g4"
#undef AE_BUFFER_VAR
#define MAKE_AE_BUFFER_POINTER() gen_rtx (REG, Pmode, 4) /* 4 = %g4 */
/* The end of the AE Buffer can either be pointed to by a register or
by a variable stored in memory. If it is in a register,
AE_BUFFER_BOUND_REG contains the register's name, as a string. If it
is in memory, AE_BUFFER_BOUND_VAR contains the variable's name as a
string. MAKE_AE_BOUND_POINTER returns an rtx expression for this
pointer. */
#define AE_BUFFER_BOUND_REG "%g6"
#undef AE_BUFFER_BOUND_VAR
#define MAKE_AE_BOUND_POINTER() gen_rtx (REG, Pmode, 6)
/* Alternatively, the end of the AE buffer can be a fixed distance
from the top of the stack. */
#undef STACK_TOP
#undef AE_BUFFER_STACK_OFFSET
/* Size of AE buffer (bytes). */
#define AE_BUFFER_SIZE 0x100000 /* 1MB */
/* Size of a stack frame for the routine AE_START. */
/* Need a 16 word window save area for SPARC */
#define AE_START_FRAME_SIZE (16 * sizeof (int))
/* Name of stack pointer register. */
#define SP_REG "%sp"
/* One plus maximum number of instructions combine by peephole optimizer. */
#define MAX_PEEP 3
/* Return non-zero if register number REGNO can be defined upon
function entry. */
#define REGISTER_DEFINED_IN_CALL(REGNO) ((REGNO) == STACK_POINTER_REGNUM \
|| (REGNO) == FRAME_POINTER_REGNUM \
|| ((REGNO) >= 24 && (REGNO) <= 31))
/* Define the characters that proceed comments and assembler directives. */
#define ASM_COMMENT_CHAR '!'
#define ASM_DIRECTIVE_CHAR '.'
/* Define the number of delayed instructions after a jump, conditional jump,
or call instruction. Do not define these values if the instructions have
no delays or the assembler hides them by doing code reorganization. */
#define JUMP_DELAY_SLOTS 1
#define CJUMP_DELAY_SLOTS 1
#define CALL_DELAY_SLOTS 1
/* The size of most assembly instructions (in bytes). */
#define STD_ASM_INSN_LENGTH 4
/* Set of instruction-size pairs for instructions whose size is not
standard. The table must be sorted by instruction name. */
#undef ASM_INSN_SIZE_EXCEPTIONS
/* Return non-zero if the assembly instruction is a branch that does
not execute its (normally) delayed slot instruction. */
#define BRANCH_IS_ANNULED(ASM_INSN) substring (ASM_INSN, ",a ")
/* Return a pointer to the function name if an assembly instruction is
a subroutine invocation. If it is not, return 0. */
#define ASM_INSN_IS_CALL(ASM_INSN) (strncmp ((ASM_INSN), "call .", 6) \
? 0 : (ASM_INSN) + 5)
/* Produce the schema corresponding the the standard function prologue
and epilogue. Record values that are need upon function entry. */
#define SCHEMA_PROLOGUE(RECORD_REG_ON_ENTRY) \
{ \
/* Code from FUNCTION_PROLOGUE: */ \
extern char call_used_regs[]; \
extern int frame_pointer_needed; \
extern rtx stack_pointer_rtx, frame_pointer_rtx; \
int n_fregs = 0, i; \
int n_iregs = 64; \
register int regno; \
int sp_schema_produced = 0, fp_schema_produced = 0; \
\
for (i = 32; i < FIRST_PSEUDO_REGISTER; i++) \
if (regs_ever_live[i] && ! call_used_regs[i]) \
n_fregs++; \
for (i = 16; i < 32; i++) \
if (regs_ever_live[i]) { n_iregs = 96; break; } \
\
if (RECORD_REG_ON_ENTRY [STACK_POINTER_REGNUM]) \
sp_schema_produced = record_sp (); \
if (RECORD_REG_ON_ENTRY [FRAME_POINTER_REGNUM]) \
fp_schema_produced = record_fp (); \
\
if (n_fregs) \
{ \
for (i = 32, n_fregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \
if (regs_ever_live[i] && ! call_used_regs[i]) \
{ \
if (!sp_schema_produced) \
sp_schema_produced = record_sp (); \
if (regs_ever_live[i+1] && ! call_used_regs[i+1]) \
{ \
store_schema_int_offset (STACK_POINTER_REGNUM, \
n_iregs + 4 * n_fregs, 0); \
n_fregs += 2, i += 1; \
} \
else \
store_schema_int_offset (STACK_POINTER_REGNUM, \
n_iregs + 4 * n_fregs++, 1); \
} \
} \
if (regs_ever_live[32]) \
{ \
if (!fp_schema_produced) \
fp_schema_produced = record_fp (); \
store_schema_int_offset (FRAME_POINTER_REGNUM, -16, 0); \
store_schema_int_offset (FRAME_POINTER_REGNUM, -12, 0); \
} \
\
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno ++) \
if (RECORD_REG_ON_ENTRY [regno]) \
if ((regno == STACK_POINTER_REGNUM && !sp_schema_produced)\
|| (regno == FRAME_POINTER_REGNUM && !fp_schema_produced) \
|| (regno != STACK_POINTER_REGNUM && regno != FRAME_POINTER_REGNUM))\
{ \
unknown_def_schema (regno); \
issue_event (gen_rtx (REG, Pmode, regno)); \
} \
}
#define SCHEMA_EPILOGUE() \
{ \
/* Code from FUNCTION_EPILOGUE: */ \
extern char call_used_regs[]; \
extern int current_function_pretend_args_size; \
int fsize = (((get_frame_size ()) + 7 - STARTING_FRAME_OFFSET)\
& -8); \
int actual_fsize; \
int n_fregs = 0, i; \
int n_iregs = 64; \
\
for (i = 32, n_fregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \
if (regs_ever_live[i] && ! call_used_regs[i]) \
n_fregs++; \
for (i = 16; i < 32; i++) \
if (regs_ever_live[i]) { n_iregs = 96; break; } \
actual_fsize = fsize + n_iregs + (n_fregs*4+7 & -8); \
actual_fsize += current_function_pretend_args_size+7 & -8; \
fsize += current_function_pretend_args_size+7 & -8; \
if (n_fregs) \
{ \
int base; \
int offset; \
if (fsize < 4096) \
{ \
base = FRAME_POINTER_REGNUM; \
offset = n_iregs - actual_fsize; \
} \
else \
{ \
base = 1; /* %g1 */ \
offset = n_iregs; \
} \
for (i = 32, n_fregs = 0; i < FIRST_PSEUDO_REGISTER; i++) \
if (regs_ever_live[i] && ! call_used_regs[i]) \
{ \
if (regs_ever_live[i+1] && ! call_used_regs[i+1]) \
{ \
load_schema_int_offset (base, offset + 4 * n_fregs, 0); \
n_fregs += 2, i += 1; \
} \
else \
load_schema_int_offset (base, offset + 4 * n_fregs++, 1);\
} \
} \
}
/* Produce and write the the assembly output file code to record the
various types of events. */
/* Check that the AE buffer has SIZE bytes free. If not, empty the
buffer. */
#define GENERATE_SPACE_CHECK(COMMENT, SIZE) \
{ \
rtx xops [2]; \
rtx label = gen_label_rtx (); \
char buffer [256]; \
\
xops [0] = ae_buffer_pointer; \
xops [1] = ae_buffer_end_pointer; \
sprintf (buffer, "subcc %%0, %%1, %%%%g0\t! %s Event", COMMENT); \
output_asm_insn (buffer, xops); \
\
xops [0] = label; \
output_asm_insn ("ble %l0", xops); \
output_asm_insn ("nop"); \
\
output_asm_insn ("call _ae_flush_buffer", xops); \
output_asm_insn ("nop"); \
\
ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (label)); \
}
/* Generate an event to record VALUE (an rtx register). */
#define GENERATE_EVENT(VALUE) \
{ \
rtx xops [2]; \
\
xops [0] = VALUE; \
output_asm_insn ("mov %0, %%g2", xops); \
xops [0] = ae_buffer_pointer; \
/* Is there a better way to do an unaligned store on a SPARC? */ \
output_asm_insn ("stb %%g2, [3 + %0]", xops); \
output_asm_insn ("srl %%g2, 8, %%g2", xops); \
output_asm_insn ("stb %%g2, [2 + %0]", xops); \
output_asm_insn ("srl %%g2, 8, %%g2", xops); \
output_asm_insn ("stb %%g2, [1 + %0]", xops); \
output_asm_insn ("srl %%g2, 8, %%g2", xops); \
output_asm_insn ("stb %%g2, [0 + %0]", xops); \
\
xops [0] = ae_buffer_pointer; \
output_asm_insn ("add %0, 4, %0\t\t! End Event", xops); \
}
/* Generate an event to record the integer VALUE, which should be
stored in BYTES bytes. */
#define GENERATE_SHORT_EVENT(VALUE, BYTES) \
{ \
xops [0] = gen_rtx (CONST_INT, VOIDmode, VALUE); \
output_asm_insn ("mov %0, %%g2", xops); \
\
xops [0] = ae_buffer_pointer; \
if (BYTES == 1) \
output_asm_insn ("stb %%g2, [0 + %0]", xops); \
else \
{ \
output_asm_insn ("stb %%g2, [1 + %0]", xops); \
output_asm_insn ("srl %%g2, 8, %%g2", xops); \
output_asm_insn ("stb %%g2, [0 + %0]", xops); \
} \
\
xops [0] = ae_buffer_pointer; \
xops [1] = gen_rtx (CONST_INT, VOIDmode, BYTES); \
output_asm_insn ("add %0, %1, %0\t\t! End Short Event", xops); \
}
/* Generate an event to record ADDRESS, which is made computed from BASE and
OFFSET. */
#define GENERATE_ADDRESS_EVENT(ADDRESS, BASE, OFFSET) \
{ \
rtx xops [2]; \
\
xops [0] = BASE; \
output_asm_insn ("sethi %%hi(%0), %%g2", xops); \
if (OFFSET != NULL) \
{ \
xops [1] = OFFSET; \
output_asm_insn ("add %%g2, %%lo(%0)+%a1, %%g2", xops); \
} \
else \
output_asm_insn ("add %%g2, %%lo(%0), %%g2", xops); \
\
xops [0] = ae_buffer_pointer; \
/* Is there a better way to do an unaligned store on a SPARC? */ \
output_asm_insn ("stb %%g2, [3 + %0]", xops); \
output_asm_insn ("srl %%g2, 8, %%g2", xops); \
output_asm_insn ("stb %%g2, [2 + %0]", xops); \
output_asm_insn ("srl %%g2, 8, %%g2", xops); \
output_asm_insn ("stb %%g2, [1 + %0]", xops); \
output_asm_insn ("srl %%g2, 8, %%g2", xops); \
output_asm_insn ("stb %%g2, [0 + %0]", xops); \
\
xops [0] = ae_buffer_pointer; \
output_asm_insn ("add %0, 4, %0\t\t! End Address Event", xops); \
}
/* Assembly code routines for aecrt0.o. */
#ifdef AE_START_ASM
.text
.align 4
.global _ae_start
.proc 1
_ae_start:
mov 0, %fp
ld [%sp + 64], %l0
add %sp, 68, %l1
sll %l0, 2, %l2
add %l2, 4, %l2
add %l1, %l2, %l2
sethi %hi(_environ), %l3
st %l2, [%l3 + %lo(_environ)]
call _ae_initialize ! Addition
nop
mov %o0, %sp ! ditto
mov %l0, %o0 ! ditto
mov %l1, %o1 ! ditto
mov %l2, %o2 ! ditto
call _main
sub %sp, 0x20, %sp
call _exit
nop
call __exit
nop
#endif
#ifdef AE_FLUSH_BUFFER_ASM
.text
.align 4
.global _ae_flush_buffer
.proc 1
_ae_flush_buffer:
!#PROLOGUE# 0
save %sp,-240,%sp
!#PROLOGUE# 1
st %g1,[%fp-144]
st %g2,[%fp-148]
st %g3,[%fp-156]
st %g5,[%fp-160]
st %g7,[%fp-164]
sethi %hi(_ae_buffer_base),%g1
ld [%g1+%lo(_ae_buffer_base)],%o2
sethi %hi(_ae_fd),%g1
ld [%g1+%lo(_ae_fd)],%o0
mov %o2,%o1
call _write,0
sub %g4,%o2,%o2
sethi %hi(_ae_buffer_base),%g1
ld [%g1+%lo(_ae_buffer_base)],%g4
sethi %hi(1048572),%g1
or %lo(1048572),%g1,%g1
add %g4,%g1,%g6
ld [%fp-144], %g1
ld [%fp-148], %g2
ld [%fp-156], %g3
ld [%fp-160], %g5
ld [%fp-164], %g7
ret
restore
.global _ae_fd
.common _ae_fd,8,"bss"
.global _ae_buffer_base
.common _ae_buffer_base,8,"bss"
#endif
/* Definitions for AEC. */
/* a.out file format is BSD, with the nlist library to find symbols. */
#undef ECOFF_AOUT
#define BSD_AOUT
/* Function call returns this many bytes after call instruction. */
#define PC_OFFSET_AFTER_CALL 8
/* Return non-zero if register N is local to a function, e.g. can
have distinct values in different functions. */
#define REG_LOCAL_TO_FUNCTION(N) ((N) >=8 && (N) <= 31)
/* Initialize registers before the generation program begins. */
#define INITIALIZE_REGISTERS() {output_set_value (0, "0");}